home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 June
/
CHIP Haziran 2001.iso
/
prog
/
haziran
/
19
/
setup.exe
/
data.z
/
pbclib.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-04-11
|
39KB
|
1,216 lines
////////////////////////////////////////////////////////////////
// File - V3pbclib.c
//
// Library for 'WinDriver for V3 Semiconductor PBC family of devices.
// The basic idea is to get a handle for the board
// with V3PBC_Open() and use it in the rest of the program
// when calling WD functions. Call V3PBC_Close() when done.
//
////////////////////////////////////////////////////////////////
#include "../../include/windrvr.h"
#include "../../include/windrvr_int_thread.h"
#include "pbclib.h"
#include <stdio.h>
// this string is set to an error message, if one occurs
CHAR V3PBC_ErrorString[1024];
// internal function used by V3PBC_Open()
BOOL V3PBC_DetectCardElements(V3PBCHANDLE hV3);
// internal function for setting remap base address
void V3PBC_SetRemapBase0(V3PBCHANDLE hV3, DWORD dwLocalAddr);
// internal implementation of active delay
void V3PBC_SleepMicro(V3PBCHANDLE hV3, DWORD nMicro);
// internal functions used for EEPROM read/write
BOOL I2C_StartSlave(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit);
BOOL I2C_PollAckStart(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit);
BOOL I2C_Write8(V3PBCHANDLE hV3,BYTE bData);
BYTE I2C_Read8(V3PBCHANDLE hV3);
void I2C_Stop(V3PBCHANDLE hV3);
void I2C_NoAck(V3PBCHANDLE hV3);
void I2C_Ack(V3PBCHANDLE hV3);
BYTE I2C_SDAIn(V3PBCHANDLE hV3);
void I2C_SDA(V3PBCHANDLE hV3, BOOL fHigh);
void I2C_SCL(V3PBCHANDLE hV3, BOOL fHigh);
void I2C_Lock(V3PBCHANDLE hV3);
void I2C_UnLock(V3PBCHANDLE hV3);
void I2C_Delay(V3PBCHANDLE hV3);
//////////////////////////////////////////////////////////////////////////////
// Card Detection/Init
//////////////////////////////////////////////////////////////////////////////
DWORD V3PBC_CountCards (DWORD dwVendorID, DWORD dwDeviceID)
{
WD_VERSION ver;
WD_PCI_SCAN_CARDS pciScan;
HANDLE hWD = INVALID_HANDLE_VALUE;
V3PBC_ErrorString[0] = '\0';
hWD = WD_Open();
// check if handle valid & version OK
if (hWD==INVALID_HANDLE_VALUE)
{
sprintf( V3PBC_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
return 0;
}
BZERO(ver);
WD_Version(hWD,&ver);
if (ver.dwVer<WD_VER)
{
sprintf( V3PBC_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
WD_Close (hWD);
return 0;
}
BZERO(pciScan);
pciScan.searchId.dwVendorId = dwVendorID;
pciScan.searchId.dwDeviceId = dwDeviceID;
WD_PciScanCards (hWD, &pciScan);
WD_Close (hWD);
if (pciScan.dwCards==0)
sprintf( V3PBC_ErrorString, "no cards found\n");
return pciScan.dwCards;
}
BOOL V3PBC_Open (V3PBCHANDLE *phV3, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions)
{
V3PBCHANDLE hV3 = (V3PBCHANDLE) malloc (sizeof (V3PBC_STRUCT));
WD_VERSION ver;
WD_PCI_SCAN_CARDS pciScan;
WD_PCI_CARD_INFO pciCardInfo;
*phV3 = NULL;
V3PBC_ErrorString[0] = '\0';
BZERO(*hV3);
hV3->cardReg.hCard = 0;
hV3->hWD = WD_Open();
// check if handle valid & version OK
if (hV3->hWD==INVALID_HANDLE_VALUE)
{
sprintf( V3PBC_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
goto Exit;
}
BZERO(ver);
WD_Version(hV3->hWD,&ver);
if (ver.dwVer<WD_VER)
{
sprintf( V3PBC_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
goto Exit;
}
pciScan.searchId.dwVendorId = dwVendorID;
pciScan.searchId.dwDeviceId = dwDeviceID;
WD_PciScanCards (hV3->hWD, &pciScan);
if (pciScan.dwCards==0) // Found at least one card
{
sprintf( V3PBC_ErrorString, "Could not find PCI card\n");
goto Exit;
}
if (pciScan.dwCards<=nCardNum)
{
sprintf( V3PBC_ErrorString, "Card out of range of available cards\n");
goto Exit;
}
BZERO(pciCardInfo);
pciCardInfo.pciSlot = pciScan.cardSlot[nCardNum];
WD_PciGetCardInfo (hV3->hWD, &pciCardInfo);
hV3->pciSlot = pciCardInfo.pciSlot;
hV3->cardReg.Card = pciCardInfo.Card;
hV3->fUseInt = (dwOptions & V3PBC_OPEN_USE_INT) ? TRUE : FALSE;
if (!hV3->fUseInt)
{
DWORD i;
// Remove interrupt item if not needed
for (i=0; i<hV3->cardReg.Card.dwItems; i++)
{
WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
if (pItem->item==ITEM_INTERRUPT)
pItem->item = ITEM_NONE;
}
}
else
{
DWORD i;
// make interrupt resource sharable
for (i=0; i<hV3->cardReg.Card.dwItems; i++)
{
WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
if (pItem->item==ITEM_INTERRUPT)
pItem->fNotSharable = FALSE;
}
}
hV3->cardReg.fCheckLockOnly = FALSE;
WD_CardRegister (hV3->hWD, &hV3->cardReg);
if (hV3->cardReg.hCard==0)
{
sprintf ( V3PBC_ErrorString, "Failed locking device\n");
goto Exit;
}
if (!V3PBC_DetectCardElements(hV3))
{
sprintf ( V3PBC_ErrorString, "Card does not have all items expected for V3 PBC\n");
goto Exit;
}
hV3->dwReg_PCI_MAP0 = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_MAP0);
// Open finished OK
*phV3 = hV3;
return TRUE;
Exit:
// Error durin Open
if (hV3->cardReg.hCard)
WD_CardUnregister(hV3->hWD, &hV3->cardReg);
if (hV3->hWD!=INVALID_HANDLE_VALUE)
WD_Close(hV3->hWD);
free (hV3);
return FALSE;
}
DWORD V3PBC_ReadPCIReg(V3PBCHANDLE hV3, DWORD dwReg)
{
WD_PCI_CONFIG_DUMP pciCnf;
DWORD dwVal;
BZERO(pciCnf);
pciCnf.pciSlot = hV3->pciSlot;
pciCnf.pBuffer = &dwVal;
pciCnf.dwOffset = dwReg;
pciCnf.dwBytes = 4;
pciCnf.fIsRead = TRUE;
WD_PciConfigDump(hV3->hWD,&pciCnf);
return dwVal;
}
void V3PBC_WritePCIReg(V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData)
{
WD_PCI_CONFIG_DUMP pciCnf;
BZERO (pciCnf);
pciCnf.pciSlot = hV3->pciSlot;
pciCnf.pBuffer = &dwData;
pciCnf.dwOffset = dwReg;
pciCnf.dwBytes = 4;
pciCnf.fIsRead = FALSE;
WD_PciConfigDump(hV3->hWD,&pciCnf);
}
BOOL V3PBC_DetectCardElements(V3PBCHANDLE hV3)
{
DWORD i;
DWORD ad_sp;
DWORD RegisterMask;
memset (&hV3->Int, 0, sizeof (hV3->Int));
memset (hV3->addrDesc, 0, sizeof (hV3->addrDesc));
for (i=0; i<hV3->cardReg.Card.dwItems; i++)
{
WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
switch (pItem->item)
{
case ITEM_MEMORY:
case ITEM_IO:
{
DWORD dwBytes;
DWORD dwAddr;
DWORD dwAddrDirect = 0;
DWORD dwPhysAddr;
BOOL fIsMemory;
if (pItem->item==ITEM_MEMORY)
{
dwBytes = pItem->I.Mem.dwBytes;
dwAddr = pItem->I.Mem.dwTransAddr;
dwAddrDirect = pItem->I.Mem.dwUserDirectAddr;
dwPhysAddr = pItem->I.Mem.dwPhysicalAddr;
fIsMemory = TRUE;
}
else
{
dwBytes = pItem->I.IO.dwBytes;
dwAddr = pItem->I.IO.dwAddr;
dwPhysAddr = dwAddr & 0xffff;
fIsMemory = FALSE;
}
for (ad_sp=V3PBC_ADDR_IO_BASE; ad_sp<=V3PBC_ADDR_ROM; ad_sp++)
{
DWORD dwPCIAddr;
DWORD dwPCIReg;
DWORD dwApertureSize;
if (hV3->addrDesc[ad_sp].dwAddr) continue;
if (ad_sp==V3PBC_ADDR_IO_BASE) dwPCIReg = V3PBC_PCI_IO_BASE;
else if (ad_sp==V3PBC_ADDR_BASE0) dwPCIReg = V3PBC_PCI_BASE0;
else if (ad_sp==V3PBC_ADDR_BASE1) dwPCIReg = V3PBC_PCI_BASE1;
else if (ad_sp==V3PBC_ADDR_ROM) dwPCIReg = V3PBC_PCI_ROM;
else continue;
dwPCIAddr = V3PBC_ReadPCIReg(hV3, dwPCIReg);
if (ad_sp==V3PBC_ADDR_IO_BASE)
{
//
// The V3PBC_PCI_IO_BASE register uses address lines 31-8 for decoding.
//
RegisterMask = (DWORD) 0xffffff00;
}
else
{
dwApertureSize = (dwPCIAddr & 0x000000f0) >> 4;
if (dwPCIAddr & 1)
{
//
// The aperture defines an I/O region
// Valid I/O values are from 4 to 7 use address lines 31-8
//
dwApertureSize -= 4;
RegisterMask = (DWORD) 0xffffff00;
}
else
{
//
// The aperture defines a memory region use address lines 31-20
//
RegisterMask = (DWORD) 0xfff00000;
}
//
// Reduce mask size base on aperture size
//
while(dwApertureSize != 0)
{
RegisterMask <<=1;
dwApertureSize--;
}
}
if (dwPCIAddr & 1)
{
if (fIsMemory) continue;
dwPCIAddr &= RegisterMask;
}
else
{
if (!fIsMemory) continue;
dwPCIAddr &= RegisterMask;
}
//
// Found Item description that matches PBC aperture settings, so break for loop
//
if (dwPCIAddr==dwPhysAddr)
break;
}
if (ad_sp<=V3PBC_ADDR_ROM)
{
DWORD j;
hV3->addrDesc[ad_sp].dwBytes = dwBytes;
hV3->addrDesc[ad_sp].dwAddr = dwAddr;
hV3->addrDesc[ad_sp].dwAddrDirect = dwAddrDirect;
hV3->addrDesc[ad_sp].fIsMemory = fIsMemory;
hV3->addrDesc[ad_sp].dwMask = 0;
for (j=1; j<hV3->addrDesc[ad_sp].dwBytes && j!=0x80000000; j *= 2)
{
hV3->addrDesc[ad_sp].dwMask =
(hV3->addrDesc[ad_sp].dwMask << 1) | 1;
}
}
}
break;
case ITEM_INTERRUPT:
if (hV3->Int.Int.hInterrupt) return FALSE;
hV3->Int.Int.hInterrupt = pItem->I.Int.hInterrupt;
break;
}
}
// check that all the items needed were found
// check if interrupt found
if (hV3->fUseInt && !hV3->Int.Int.hInterrupt)
{
return FALSE;
}
// check that the registers space was found
if (!V3PBC_IsAddrSpaceActive(hV3, V3PBC_ADDR_IO_BASE)
|| hV3->addrDesc[V3PBC_ADDR_IO_BASE].dwBytes!=V3PBC_RANGE_REG)
return FALSE;
// check that at least one memory space was found
for (i = V3PBC_ADDR_IO_BASE; i<=V3PBC_ADDR_ROM; i++)
if (V3PBC_IsAddrSpaceActive(hV3, i)) break;
if (i>V3PBC_ADDR_ROM) return FALSE;
return TRUE;
}
void V3PBC_Close(V3PBCHANDLE hV3)
{
// disable interrupts
if (V3PBC_IntIsEnabled(hV3))
V3PBC_IntDisable(hV3);
// unregister card
if (hV3->cardReg.hCard)
WD_CardUnregister(hV3->hWD, &hV3->cardReg);
// close WinDriver
WD_Close(hV3->hWD);
free (hV3);
}
BOOL V3PBC_IsAddrSpaceActive(V3PBCHANDLE hV3, V3PBC_ADDR addrSpace)
{
return hV3->addrDesc[addrSpace].dwAddr!=0;
}
DWORD V3PBC_GetRevision(V3PBCHANDLE hV3)
{
DWORD dwRev = V3PBC_ReadRegDWord(hV3, V3PBC_PCI_CC_REV);
return dwRev & 0xf;
}
//////////////////////////////////////////////////////////////////////////////
// Access Registers range
//////////////////////////////////////////////////////////////////////////////
void V3PBC_WriteRegDWord (V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData)
{
V3PBC_WriteSpaceDWord (hV3, V3PBC_ADDR_IO_BASE, dwReg, dwData);
}
DWORD V3PBC_ReadRegDWord (V3PBCHANDLE hV3, DWORD dwReg)
{
return V3PBC_ReadSpaceDWord(hV3, V3PBC_ADDR_IO_BASE, dwReg);
}
void V3PBC_WriteRegWord (V3PBCHANDLE hV3, DWORD dwReg, WORD wData)
{
V3PBC_WriteSpaceWord (hV3, V3PBC_ADDR_IO_BASE, dwReg, wData);
}
WORD V3PBC_ReadRegWord (V3PBCHANDLE hV3, DWORD dwReg)
{
return V3PBC_ReadSpaceWord(hV3, V3PBC_ADDR_IO_BASE, dwReg);
}
void V3PBC_WriteRegByte (V3PBCHANDLE hV3, DWORD dwReg, BYTE bData)
{
V3PBC_WriteSpaceByte (hV3, V3PBC_ADDR_IO_BASE, dwReg, bData);
}
BYTE V3PBC_ReadRegByte (V3PBCHANDLE hV3, DWORD dwReg)
{
return V3PBC_ReadSpaceByte(hV3, V3PBC_ADDR_IO_BASE, dwReg);
}
//////////////////////////////////////////////////////////////////////////////
// Access Local range
//////////////////////////////////////////////////////////////////////////////
void V3PBC_SetRemapBase0(V3PBCHANDLE hV3, DWORD dwLocalAddr)
{
DWORD dwMapRegValue = hV3->dwReg_PCI_MAP0;
dwMapRegValue |= (~hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask) & dwLocalAddr;
V3PBC_WriteRegDWord( hV3, V3PBC_PCI_MAP0, dwMapRegValue);
}
void V3PBC_WriteDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, DWORD dwData)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
V3PBC_WriteSpaceDWord (hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, dwData);
}
DWORD V3PBC_ReadDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
return V3PBC_ReadSpaceDWord(hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
}
void V3PBC_WriteWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, WORD wData)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
V3PBC_WriteSpaceWord (hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, wData);
}
WORD V3PBC_ReadWord (V3PBCHANDLE hV3, DWORD dwLocalAddr)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
return V3PBC_ReadSpaceWord(hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
}
void V3PBC_WriteByte (V3PBCHANDLE hV3, DWORD dwLocalAddr, BYTE bData)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
V3PBC_WriteSpaceByte (hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, bData);
}
BYTE V3PBC_ReadByte (V3PBCHANDLE hV3, DWORD dwLocalAddr)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
return V3PBC_ReadSpaceByte(hV3, V3PBC_ADDR_BASE0,
hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
}
void V3PBC_ReadBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
V3PBC_ReadSpaceBlock(hV3, hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr,
buf, dwBytes, V3PBC_ADDR_BASE0);
}
void V3PBC_WriteBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes)
{
V3PBC_SetRemapBase0(hV3, dwLocalAddr);
V3PBC_WriteSpaceBlock(hV3, hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr,
buf, dwBytes, V3PBC_ADDR_BASE0);
}
//////////////////////////////////////////////////////////////////////////////
// Access Address space (low-level functions)
//////////////////////////////////////////////////////////////////////////////
// Note: addrSpace is a base address register
BYTE V3PBC_ReadSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
BYTE *pByte = (BYTE *) dwAddr;
return *pByte;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = RP_BYTE;
trans.dwPort = dwAddr;
WD_Transfer (hV3->hWD, &trans);
return trans.Data.Byte;
}
}
void V3PBC_WriteSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, BYTE data)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
BYTE *pByte = (BYTE *) dwAddr;
*pByte = data;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = WP_BYTE;
trans.dwPort = dwAddr;
trans.Data.Byte = data;
WD_Transfer (hV3->hWD, &trans);
}
}
WORD V3PBC_ReadSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WORD *pWord = (WORD *) dwAddr;
return *pWord;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = RP_WORD;
trans.dwPort = dwAddr;
WD_Transfer (hV3->hWD, &trans);
return trans.Data.Word;
}
}
void V3PBC_WriteSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, WORD data)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WORD *pWord = (WORD *) dwAddr;
*pWord = data;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = WP_WORD;
trans.dwPort = dwAddr;
trans.Data.Word = data;
WD_Transfer (hV3->hWD, &trans);
}
}
DWORD V3PBC_ReadSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
DWORD *pDword = (DWORD *) dwAddr;
return *pDword;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = RP_DWORD;
trans.dwPort = dwAddr;
WD_Transfer (hV3->hWD, &trans);
return trans.Data.Dword;
}
}
void V3PBC_WriteSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, DWORD data)
{
if (hV3->addrDesc[addrSpace].fIsMemory)
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
DWORD *pDword = (DWORD *) dwAddr;
*pDword = data;
}
else
{
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
WD_TRANSFER trans;
BZERO(trans);
trans.cmdTrans = WP_DWORD;
trans.dwPort = dwAddr;
trans.Data.Dword = data;
WD_Transfer (hV3->hWD, &trans);
}
}
void V3PBC_ReadWriteSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf,
DWORD dwBytes, BOOL fIsRead, V3PBC_ADDR addrSpace, V3PBC_MODE mode)
{
WD_TRANSFER trans;
DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
(hV3->addrDesc[addrSpace].dwMask & dwOffset);
BZERO(trans);
if (hV3->addrDesc[addrSpace].fIsMemory)
{
if (fIsRead)
{
if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = RM_SBYTE;
else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = RM_SWORD;
else trans.cmdTrans = RM_SDWORD;
}
else
{
if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = WM_SBYTE;
else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = WM_SWORD;
else trans.cmdTrans = WM_SDWORD;
}
}
else
{
if (fIsRead)
{
if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = RP_SBYTE;
else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = RP_SWORD;
else trans.cmdTrans = RP_SDWORD;
}
else
{
if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = WP_SBYTE;
else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = WP_SWORD;
else trans.cmdTrans = WP_SDWORD;
}
}
trans.dwPort = dwAddr;
trans.fAutoinc = TRUE;
trans.dwBytes = dwBytes;
trans.dwOptions = 0;
trans.Data.pBuffer = buf;
WD_Transfer (hV3->hWD, &trans);
}
void V3PBC_ReadSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf,
DWORD dwBytes, V3PBC_ADDR addrSpace)
{
V3PBC_ReadWriteSpaceBlock (hV3, dwOffset, buf, dwBytes, TRUE, addrSpace, V3PBC_MODE_DWORD);
}
void V3PBC_WriteSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf,
DWORD dwBytes, V3PBC_ADDR addrSpace)
{
V3PBC_ReadWriteSpaceBlock (hV3, dwOffset, buf, dwBytes, FALSE, addrSpace, V3PBC_MODE_DWORD);
}
//////////////////////////////////////////////////////////////////////////////
// Interrupts
//////////////////////////////////////////////////////////////////////////////
BOOL V3PBC_IntIsEnabled (V3PBCHANDLE hV3)
{
if (!hV3->fUseInt) return FALSE;
if (!hV3->Int.hThread) return FALSE;
return TRUE;
}
VOID V3PBC_IntHandler (PVOID pData)
{
V3PBCHANDLE hV3 = (V3PBCHANDLE) pData;
V3PBC_INT_RESULT intResult;
intResult.dwCounter = hV3->Int.Int.dwCounter;
intResult.dwLost = hV3->Int.Int.dwLost;
intResult.fStopped = hV3->Int.Int.fStopped;
intResult.dwStatusReg = hV3->Int.Trans[0].Data.Dword;
hV3->Int.funcIntHandler(hV3, &intResult);
}
BOOL V3PBC_IntEnable (V3PBCHANDLE hV3, V3PBC_INT_HANDLER funcIntHandler)
{
DWORD dwIntStatus;
DWORD dwAddr;
if (!hV3->fUseInt) return FALSE;
// check if interrupt is already enabled
if (hV3->Int.hThread) return FALSE;
dwIntStatus = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_BPARM);
BZERO(hV3->Int.Trans);
// This is a samlpe of handling interrupts:
// Two transfer commands are issued. First the value of the interrrupt control/status
// register is read. Then, a value of ZERO is written.
// This will cancel interrupts after the first interrupt occurs.
// When using interrupts, this section will have to change:
// you must put transfer commands to CANCEL the source of the interrupt, otherwise, the
// PC will hang when an interrupt occurs!
dwAddr = hV3->addrDesc[V3PBC_ADDR_IO_BASE].dwAddr + V3PBC_PCI_BPARM;
hV3->Int.Trans[0].cmdTrans = hV3->addrDesc[V3PBC_ADDR_IO_BASE].fIsMemory ? RM_DWORD : RP_DWORD;
hV3->Int.Trans[0].dwPort = dwAddr;
hV3->Int.Trans[1].cmdTrans = hV3->addrDesc[V3PBC_ADDR_IO_BASE].fIsMemory ? WM_DWORD : WP_DWORD;
hV3->Int.Trans[1].dwPort = dwAddr;
hV3->Int.Trans[1].Data.Dword = dwIntStatus & ~BIT8; // put here the data to write to the control register
hV3->Int.Int.dwCmds = 2;
hV3->Int.Int.Cmd = hV3->Int.Trans;
hV3->Int.Int.dwOptions |= INTERRUPT_CMD_COPY;
// this calls WD_IntEnable() and creates an interrupt handler thread
hV3->Int.funcIntHandler = funcIntHandler;
if (!InterruptThreadEnable(&hV3->Int.hThread, hV3->hWD, &hV3->Int.Int, V3PBC_IntHandler, (PVOID) hV3))
return FALSE;
// this enables interrupts
// Enable INTA to interrupt the PCI bus
V3PBC_WriteRegDWord (hV3, V3PBC_PCI_BPARM, dwIntStatus | BIT8);
return TRUE;
}
void V3PBC_IntDisable (V3PBCHANDLE hV3)
{
DWORD dwIntStatus;
if (!hV3->fUseInt) return;
if (!hV3->Int.hThread) return;
// this disables interrupts
// Disable interrupt assumes INTA was enabled
dwIntStatus = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_BPARM);
V3PBC_WriteRegDWord (hV3, V3PBC_PCI_BPARM, dwIntStatus & ~BIT8);
// this calls WD_IntDisable()
InterruptThreadDisable(hV3->Int.hThread);
hV3->Int.hThread = NULL;
}
//////////////////////////////////////////////////////////////////////////////
// DMA
//////////////////////////////////////////////////////////////////////////////
BOOL V3PBC_DMAOpen(V3PBCHANDLE hV3, WD_DMA *pDMA, DWORD dwBytes)
{
V3PBC_ErrorString[0] = '\0';
BZERO(*pDMA);
pDMA->pUserAddr = NULL; // the kernel will allocate the buffer
pDMA->dwBytes = dwBytes; // size of buffer to allocate
pDMA->dwOptions = DMA_KERNEL_BUFFER_ALLOC;
WD_DMALock (hV3->hWD, pDMA);
if (!pDMA->hDma)
{
sprintf (V3PBC_ErrorString, "Failed allocating the buffer!\n");
return FALSE;
}
return TRUE;
}
void V3PBC_DMAClose(V3PBCHANDLE hV3, WD_DMA *pDMA)
{
WD_DMAUnlock (hV3->hWD, pDMA);
}
BOOL V3PBC_DMAStart(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel, WD_DMA *pDMA, BOOL fRead,
BOOL fBlocking, DWORD dwBytes, DWORD dwOffset, DWORD dwLocalAddr)
{
DWORD dwDMACSR0;
DWORD dwChannelOffset = dmaChannel*0x10;
V3PBC_WriteRegDWord(hV3, V3PBC_DMA_LOCAL_ADDR0 + dwChannelOffset, dwLocalAddr);
V3PBC_WriteRegDWord(hV3, V3PBC_DMA_PCI_ADDR0 + dwChannelOffset,
(DWORD) pDMA->Page[0].pPhysicalAddr + dwOffset);
// BIT[0-23] count is in DWORDS divide by 4
// BIT24 - initiate transfer (write)
// BIT24 - DMA transfer busy (read)
// BIT28 - transfer direction
// Preserve chain, priority and byte swapping
dwDMACSR0 = V3PBC_ReadRegDWord(hV3, V3PBC_DMA_LENGTH0 + dwChannelOffset) & 0xac00000;
V3PBC_WriteRegDWord(hV3, V3PBC_DMA_LENGTH0 + dwChannelOffset, (fRead ? 0 : BIT28) | BIT24 | dwBytes >> 2 | dwDMACSR0);
// if blocking then check BIT24 to wait for transfer to complete
if (fBlocking)
while (!V3PBC_DMAIsDone(hV3, dmaChannel));
return TRUE;
}
BOOL V3PBC_DMAIsDone(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel)
{
if (V3PBC_ReadRegDWord(hV3, V3PBC_DMA_LENGTH0 + dmaChannel*0x10) & BIT24)
return FALSE;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// Card Reset
//////////////////////////////////////////////////////////////////////////////
void V3PBC_PulseLocalReset(V3PBCHANDLE hV3, WORD wDelay)
{
WORD System;
// Unlock the system register
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, SYSTEM_UNLOCK_TOKEN);
// Assert the local reset line
System = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
V3PBC_WriteRegWord((V3PBCHANDLE) hV3, V3PBC_SYSTEM, (WORD) (System & ~SYSTEM_RST_OUT));
// Lock the system register
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_LOCK));
// Delay
V3PBC_SleepMicro(hV3, ((DWORD) wDelay) * 1000);
// Unlock the system register
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, SYSTEM_UNLOCK_TOKEN);
// De-assert the local reset line
System = V3PBC_ReadRegWord(hV3, (WORD) V3PBC_SYSTEM);
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_RST_OUT));
// Lock the system register
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_LOCK));
}
//////////////////////////////////////////////////////////////////////////////
// Sleep (delay)
//////////////////////////////////////////////////////////////////////////////
void V3PBC_SleepMicro(V3PBCHANDLE hV3, DWORD nMicro)
{
WD_SLEEP sleep;
BZERO (sleep);
sleep.dwMicroSeconds = nMicro;
WD_Sleep( hV3->hWD, &sleep);
}
//////////////////////////////////////////////////////////////////////////////
// EEPROM read/write
//////////////////////////////////////////////////////////////////////////////
// Note: V3PBC_EEPROMInit should be called for each board.
// This routine will force a stop condition on the I2C bus.
// The clock and data lines will be left high and this routine will
// return after a half clock.
void V3PBC_EEPROMInit(V3PBCHANDLE hV3)
{
// Unlock the system register
I2C_UnLock(hV3);
// Ensure that the I2C clock and data lines are in a known state
I2C_Stop(hV3);
I2C_Delay(hV3);
// Lock the system register
I2C_Lock(hV3);
}
// Parameters:
// BYTE bSlaveAddr - 3 bit address of device been selected
// BYTE bAddr - address of EEPROM location to be read from
// BYTE bData - value to be written to EEPROM
//
// Return:
// BOOL fStatus - TRUE if read successful
//
// Description:
// This routine writes a byte to the slave device's address specified.
// This routine uses the Write Byte method from the Atmel documentation.
BOOL V3PBC_EEPROMWrite(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE bData)
{
BOOL fStatus = TRUE;
// Set upper device address
bSlaveAddr |= I2C_1010;
// Unlock the system register
I2C_UnLock(hV3);
// Send device Address and wait for Ack, bAddr is sent as a write
if (!I2C_PollAckStart(hV3, bSlaveAddr, I2C_WRITE))
fStatus = FALSE;
else
{
// Send bAddr as the address to write
if (!I2C_Write8(hV3, bAddr))
fStatus = FALSE;
else
{
// Send the value to write
if (!I2C_Write8(hV3, bData))
fStatus = FALSE;
}
}
// Clean up the bus with a stop condition
I2C_Stop(hV3);
// Lock the system register
I2C_Lock(hV3);
return fStatus;
}
// Parameters:
// BYTE bSlaveAddr - 3 bit address of device been selected
// BYTE bAddr - address of EEPROM location to be read from
// BYTE *bData - EEPROM data read back (pointer to data passed)
//
// Return:
// BOOL fStatus - TRUE if read successful
//
// Description:
// This routine reads back a byte from the slave device's address
// specificed. This routine uses the Random Read method in the Atmel
// documentation.
BOOL V3PBC_EEPROMRead(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE *bData)
{
BOOL fStatus = TRUE;
// Set upper device address
bSlaveAddr |= I2C_1010;
// Unlock the system register
I2C_UnLock(hV3);
// Send device Address and wait for Ack, bAddr is sent as a write
if (!I2C_PollAckStart(hV3, bSlaveAddr, I2C_WRITE))
fStatus = FALSE;
else
{
// Send bAddr as the random address to be read
if (!I2C_Write8(hV3, bAddr))
fStatus = FALSE;
else
{
// Send a START condition and device address this time as read
if (!I2C_StartSlave(hV3, bSlaveAddr, I2C_READ))
fStatus = FALSE;
else
// read the date back from EEPROM
*bData = I2C_Read8(hV3);
}
}
// clean up bus with a NaK and Stop condition
I2C_NoAck(hV3);
I2C_Stop(hV3);
// Lock the system register
I2C_Lock(hV3);
return fStatus;
}
// Parameters:
// BYTE bAddr - 3 bit address of device been selected
// bit ReadBit - Set if command is to be a read, reset if command is a write
//
// Return:
// TRUE - read was successful
// FALSE - if negative acknowledge was received
//
// Description:
// All commands are preceded by the start condition, which is a high
// to low transition of SDA when SCL is high. All I2C devices
// continuously monitor the SDA and SCL lines for the start condition
// and will not respond to any command until this condition has been met.
//
// Once a device detects that it is being addressed it outputs an
// acknowledge on the SDA line. Depending on the state of the read/write
// bit, the device will execute a read or write operation.
//
// +-----+-----+-----+-----+-----+-----+-----+-----+
// | SA6 | SA5 | SA4 | SA3 | SA2 | SA1 | SA0 | R/W |
// +-----+-----+-----+-----+-----+-----+-----+-----+
// |--- 1=read, 0=write
BOOL I2C_StartSlave(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit)
{
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
I2C_SDA(hV3, FALSE);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
I2C_Delay(hV3);
return I2C_Write8(hV3, (BYTE) (bAddr<<1 | ReadBit));
}
// Parameters:
// V3PBCHANDLE hV3 - Handle to PBC32 data structure.
// BYTE bAddr - 3 bit address of device been selected
// bit ReadBit - Set if command is to be a read, reset if command is a write
//
// Return:
// FALSE - device is not responding (retried out)
// TRUE - read was successful
//
// Description:
// This routine checks the status of the device being written to by
// issuing a start condition followed by check for ACK. If the slave
// device is unable to communicate, the write command will not be
// acknowledged and we should wait. This routine will try I2C_RETRY times for
// an ACK before returning a I2C_BUSY indication.
BOOL I2C_PollAckStart(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit)
{
BYTE bTries = I2C_RETRY;
do
{
I2C_SDA(hV3, FALSE);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
I2C_Delay(hV3);
if (I2C_Write8(hV3, (BYTE) (bAddr<<1 | ReadBit)))
return TRUE;
}
while(bTries--);
return FALSE;
}
// Reads eight bits from the I2C bus.
// Return: BYTE bData - returns a byte of data
BYTE I2C_Read8(V3PBCHANDLE hV3)
{
BYTE i, bData=0;
I2C_SDA(hV3, TRUE);
for (i=8; i; --i )
{
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
bData = (bData<<1) | I2C_SDAIn(hV3);
I2C_SCL(hV3, FALSE);
I2C_Delay(hV3);
}
return bData;
}
// Return:
// TRUE - OK
// FALSE - BUSY or negative acknowledge
//
// Description:
// This routine writes out all 8 bits of data out to the I2C bus. After
// writing out the data, the routine reads the ACK/NACK response back and
// returns it to the caller.
BOOL I2C_Write8(V3PBCHANDLE hV3,BYTE bData)
{
BYTE bAck;
BYTE i;
for (i=0x80; i; i >>=1 )
{
I2C_SDA(hV3, (i & bData) ? TRUE : FALSE);
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
I2C_Delay(hV3);
}
I2C_SDA(hV3, TRUE);
I2C_SCL(hV3, TRUE);
bAck= I2C_SDAIn(hV3);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
I2C_Delay(hV3);
return bAck==0;
}
// All communications must be terminated by a stop condition which
// is a low to high transition of SDA while SCL is high. A stop
// condition can only be issued after the transmitting device has
// released the bus.
void I2C_Stop(V3PBCHANDLE hV3)
{
I2C_SDA(hV3, FALSE);
I2C_Delay(hV3);
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
I2C_SDA(hV3, TRUE);
}
// The No-Acknowledge is a software convention used to indicate
// unsucessful data transfers. The transmitting device, either
// master or slave, will release the bus after transmitting
// eight bits. During the ninth clock cycle the receiver will
// pull the SDA line high to indicate that it did not received the
// eight bits of data.
void I2C_NoAck(V3PBCHANDLE hV3)
{
I2C_SDA(hV3, TRUE);
I2C_Delay(hV3);
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
}
// Acknowledge is a software convention used to indicate
// sucessful data transfers. The transmitting device, either
// master or slave, will release the bus after transmitting
// eight bits. During the ninth clock cycle the receiver will
// pull the SDA line low to acknowledge that it received the
// eight bits of data.
void I2C_Ack(V3PBCHANDLE hV3)
{
I2C_SDA(hV3, FALSE);
I2C_Delay(hV3);
I2C_SCL(hV3, TRUE);
I2C_Delay(hV3);
I2C_SCL(hV3, FALSE);
}
// This routine returns the state of the Serial Data line
// Return: BYTE bData - state of the Serial Data line
BYTE I2C_SDAIn(V3PBCHANDLE hV3)
{
WORD wSystem;
wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
return ((wSystem & SYSTEM_SDA_IN) >> SYSTEM_SDA_IN_SHIFT);
}
// This routine sets the Serial Data line to the desired state.
//
// Parameters:
// BOOL fHigh - what state the SDA is to be set to
void I2C_SDA(V3PBCHANDLE hV3, BOOL fHigh)
{
WORD wSystem;
wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
if(fHigh)
wSystem |= SYSTEM_SDA_OUT;
else
wSystem &= ~SYSTEM_SDA_OUT;
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, wSystem);
}
// This routine sets the Serial Clock line to the desired state.
//
// Parameters:
// BOOL fHigh - what state the SCL is to be set to
void I2C_SCL(V3PBCHANDLE hV3, BOOL fHigh)
{
WORD wSystem;
wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
if(fHigh)
wSystem |= SYSTEM_SCL;
else
wSystem &= ~SYSTEM_SCL;
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, wSystem);
}
// This routine disables the Serial Clock pin, and sets the sytem
// lock bit.
void I2C_Lock(V3PBCHANDLE hV3)
{
WORD wSystem;
wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem & ~SYSTEM_SPROM_EN));
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem | SYSTEM_LOCK));
}
// This routine enable the sytem register for writting, and enables
// the Serial Clock output pin.
void I2C_UnLock(V3PBCHANDLE hV3)
{
WORD wSystem;
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, SYSTEM_UNLOCK_TOKEN);
wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem |SYSTEM_SPROM_EN));
}
// This routine inserts delay. 0.005 Milliseconds is enough time
void I2C_Delay(V3PBCHANDLE hV3)
{
V3PBC_SleepMicro(hV3, 5);
}